import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;

public class BattingOrderOptimizer extends Thread {
	private final ArrayList<Player>      playerAL;
	private ArrayList<PopulationMember>  popMemAL;
	private int                          population;
	private ListGUI                      target_frame;
	private boolean                      active;
	private String                        writeDir;

	public BattingOrderOptimizer(ArrayList<Player> selectedList){
		this.target_frame = null;
		this.population   = 30; // this is how many people we have.
		this.playerAL     = new ArrayList<Player>(selectedList);
		this.popMemAL     = new ArrayList<PopulationMember>();
		for(int i = 0; i < this.population; ++i){
			PopulationMember newPopMem = new PopulationMember(this.referencePlayers(this.randomBattingOrder(selectedList.size())));
			popMemAL.add(newPopMem);
		}
		this.writeDir = "C:\\Cerrano\\";
	}

	public void linkListGUI( ListGUI l ) {
		this.target_frame = l;
	}

	public  ArrayList<Integer> randomBattingOrder(int sizeOfSelectedList){
		ArrayList<Integer> tempRandomAL = new ArrayList<Integer>();
		// completely random no reference whatsoever to the selected list at this point.
		while(sizeOfSelectedList > tempRandomAL.size()){
			//used random class because math.random didnt work :-( 
			Random rand = new Random();
			int r = rand.nextInt(sizeOfSelectedList) ;
			if(!tempRandomAL.contains(r)){
				tempRandomAL.add(r);
			}
		}
		return tempRandomAL;
	}

	//References the Index of Players with respect to the inital selectedList from the ListGUI
	public ArrayList<Player> referencePlayers(ArrayList<Integer> playerIndexAL){
		ArrayList<Player> submitToTagsLineup = new ArrayList<Player>();
		System.out.println(playerIndexAL);	
		for(int i =0; i < playerIndexAL.size(); i++)
			submitToTagsLineup.add(playerAL.get(playerIndexAL.get(i)));
		return submitToTagsLineup;
	}

	public void decap_chicken() {
		this.active = false;
		System.out.println("Waiting for generation to end");
	}

	// Beginning of the Genetic Algorithm
	public void run (){
		this.active = true;
		int run = 0;
		while ( this.active ) {
			try {
				run++;
				this.target_frame.addTextular("Starting a new Generation\n");
				System.out.println("Simulating games. Please hold.");
				double total_avg = 0;
				for ( int i = 0; i < popMemAL.size(); ++i ){
					total_avg += popMemAL.get(i).evaluate(); 
				}
				System.out.println("Finished a generation");

				if ( ! this.active ) {
					break;
				}
				double the_bar = ( total_avg / this.popMemAL.size() );
				System.out.println("We're killing off all games below " + the_bar );
				this.target_frame.textClear();
				this.target_frame.addTextular("Our standard: " + the_bar + "\n");
				ArrayList<PopulationMember> neo_population = new ArrayList<PopulationMember>();
				File output = new File(this.writeDir + run + ".html");
				output.createNewFile();
				FileWriter html = new FileWriter(output);
				html.write("<html><head><title>Run " + run + "</title>");
				html.write("<style>.fit{background-color:#00FF00;}.unfit{background-color:#FF0000;}.no-room{background-color:#FFFF00; }</style>");
				html.write("</head><body>\n" );
				html.write("<h1>Results from run " + run + "</h1>" );
				html.write("<a href = '" + (run+1) + ".html' >next</a>" );
				if ( run-1 > 0 )
					html.write(" | <a href = '" + (run-1) + ".html' >prev</a>" );
				html.write("<table>\n");
				for ( int i = 0; i < popMemAL.size(); ++i ){
					if ( this.popMemAL.get(i).evaluate() < the_bar ) {
						html.write("<tr class = 'unfit' ><td>Unfit.</td><td>" + this.popMemAL.get(i).toString() + "</td></tr>");
					} else {
						if ( neo_population.size() > (( this.population / 2 ) -1 ) ) {
							// damn. Oh well. Not enough food or something.
							html.write("<tr class = 'no-room' ><td>Fit, but not enough room.</td><td>" + this.popMemAL.get(i).toString() + "</td></tr>");
						} else {
							neo_population.add( new PopulationMember(this.popMemAL.get(i).getPlayerDNA()));
							html.write("<tr class = 'fit' ><td>Fit.</td><td>" + this.popMemAL.get(i).toString() + "</td></tr>");
						}
					}
				}
				for ( int i = 0; ( neo_population.size() < (( this.population / 2 ) -1 ) ); ++i ) {
					neo_population.add(
							new PopulationMember(
									this.referencePlayers(
											this.randomBattingOrder(this.playerAL.size())
									)
							));
				}
				html.write("</table>\n");
				System.out.println("Best count: " + neo_population.size());
				for ( int i = 0; neo_population.size() < this.population; ++i ){ // half of 'em
					int offset = -1;
					if ( (this.popMemAL.size() - 1) > 0 )
						offset = (this.popMemAL.size() - 1);
					else
						offset = 0;
					PopulationMember offspring =
						this.popMemAL.get(i % offset ).mate(
								this.popMemAL.get( ( i + 1 ) % offset )
						);
					neo_population.add(offspring);
				}
				html.write("</body></html>\n");
				html.close();
				this.popMemAL = neo_population;
			} catch (IOException e) {
			}
		}
		this.target_frame.textClear();
		ArrayList<PopulationMember> unit_converter = new ArrayList<PopulationMember>();
		int bless_the_chicken = 5;
		System.out.println("Finding the " + bless_the_chicken + " top rosters");
		while ( bless_the_chicken > 0 ) {
			PopulationMember top_dog = this.popMemAL.get(0);
			System.out.println("Finding next highest lineup ( #" + bless_the_chicken + " )");
			for ( int i = 0; i < this.popMemAL.size(); ++i ) {
				if ( top_dog.evaluate() < this.popMemAL.get(i).evaluate() ) {
					top_dog = this.popMemAL.get(i);
				}
			}
			unit_converter.add(top_dog);
			this.popMemAL.remove(top_dog);
			--bless_the_chicken;
		}
		String output = "";
		for ( int i = 0; i < unit_converter.size(); ++i ) {
			output += unit_converter.get(i).toString() + "\n";
		}
		this.target_frame.addTextular(output);
	}
}
